package com.ums.upos.service;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.LocalServerSocket;
import android.net.LocalSocket;
import android.net.wifi.WifiManager;
import android.net.wifi.p2p.WifiP2pManager;
import android.os.RemoteException;

import com.ums.upos.uapi.ServiceResult;
import com.ums.upos.uapi.device.wifiprobe.OnSwitchListener;
import com.ums.upos.uapi.device.wifiprobe.OnTaskStaListener;
import com.ums.upos.uapi.device.wifiprobe.WiFiProbeService;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import rx.Emitter;
import rx.Observable;
import rx.Subscription;
import rx.exceptions.Exceptions;
import rx.functions.Action1;
import rx.functions.Cancellable;
import rx.functions.Func1;
import rx.schedulers.Schedulers;


/**
 * Created by menha on 2017/11/3.
 */

public class WifiProbeBinder extends WiFiProbeService.Stub {
    private final static Logger log = LoggerFactory.getLogger("WifiProbeBinder");
    private Context mContext;
    private WifiP2pManager mWifiP2pManager;
    private WifiP2pManager.Channel mChannel;
    private WifiManager mWifiManager;
    private Set<OnTaskStaListener> onTaskStaListenerSet = new HashSet<>();
    public static final String AUTOMMI_SOCKET_NAME = "wifi_probe_socket";
    private Subscription getStaSubscription;
    private static LocalServerSocket mServerSocket;
    private static LocalSocket mSocket;
    private BufferedReader br;

    WifiProbeBinder(Context context) {
        mContext = context;
        mWifiP2pManager = (WifiP2pManager) context.getSystemService(Context.WIFI_P2P_SERVICE);
        mChannel = mWifiP2pManager.initialize(context, context.getMainLooper(), null);
        mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
    }

    @Override
    public void openWifiStaProbe(final OnSwitchListener icb) throws RemoteException {
        log.debug("call openWifiStaProbe");
        if (mWifiManager.getWifiState() != WifiManager.WIFI_STATE_ENABLED &&
                mWifiManager.getWifiState() != WifiManager.WIFI_STATE_ENABLING)
            mWifiManager.setWifiEnabled(true);
        Observable.create(new Action1<Emitter<Intent>>() {
            @Override
            public void call(final Emitter<Intent> emitter) {
                final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
                    @Override
                    public void onReceive(Context context, Intent intent) {
                        log.debug("call BroadcastReceiver onReceive");
                        String action = intent.getAction();
                        if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
                            int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
                            log.debug("call BroadcastReceiver WIFI_P2P_STATE_CHANGED_ACTION state:{}", state);
                            if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
                                emitter.onNext(intent);
                                emitter.onCompleted();
                            }
                        }
                    }
                };
                final Context context = mContext;
                emitter.setCancellation(new Cancellable() {
                    @Override
                    public void cancel() throws Exception {
                        log.debug("call unregisterReceiver");
                        context.unregisterReceiver(broadcastReceiver);
                    }
                });
                IntentFilter mIntentFilter = new IntentFilter(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
                log.debug("call registerReceiver");
                context.registerReceiver(broadcastReceiver, mIntentFilter);
            }
        }, Emitter.BackpressureMode.BUFFER)
                .timeout(60, TimeUnit.SECONDS)
                .flatMap(new Func1<Intent, Observable<Integer>>() {
                    @Override
                    public Observable<Integer> call(Intent intent) {
                        log.debug("call flatMap");
                        return Observable.create(new Action1<Emitter<Integer>>() {
                            @Override
                            public void call(final Emitter<Integer> emitter) {
                                log.debug("call createGroup");
                                mWifiP2pManager.createGroup(mChannel, new WifiP2pManager.ActionListener() {
                                    @Override
                                    public void onSuccess() {
                                        log.debug("call createGroup onSuccess");
                                        emitter.onNext(0);
                                        emitter.onCompleted();
                                    }

                                    @Override
                                    public void onFailure(int reason) {
                                        log.debug("call createGroup onFailure,reason:{}", reason);
                                        if (reason == WifiP2pManager.BUSY)
                                            emitter.onNext(0);
                                        else
                                            emitter.onNext(-1);
                                        emitter.onCompleted();
                                    }
                                });
                            }
                        }, Emitter.BackpressureMode.BUFFER);
                    }
                })
                .subscribe(new Action1<Integer>() {
                    final OnSwitchListener onSwitchListener = icb;

                    @Override
                    public void call(Integer integer) {
                        log.debug("call observer onNext, integer:{}", integer);
                        try {
                            if (0 == integer)
                                onSwitchListener.swich(ServiceResult.WiFiProbe_Open_Succeed, "开启探针成功");
                            else
                                onSwitchListener.swich(ServiceResult.WiFiProbe_Open_Failed, "开启探针失败");
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                    }
                }, new Action1<Throwable>() {
                    final OnSwitchListener onSwitchListener = icb;

                    @Override
                    public void call(Throwable throwable) {
                        log.debug("call observer onError, throwable:{}", throwable);
                        try {
                            onSwitchListener.swich(ServiceResult.WiFiProbe_Open_Failed, "开启探针失败");
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                    }
                });
    }

    @Override
    public void closeWifiStaProbe(final OnSwitchListener icb) throws RemoteException {
        log.debug("call closeWifiStaProbe");
        if (getStaSubscription != null && !getStaSubscription.isUnsubscribed()) {
            getStaSubscription.unsubscribe();
        }
        mWifiP2pManager.removeGroup(mChannel, null);
        onTaskStaListenerSet.clear();
        if (icb != null)
            icb.swich(ServiceResult.WiFiProbe_Close_Succeed, "关闭探针成功");
    }

    private void closeReader() {
        log.debug("call closeReader");
        if (mSocket != null) {
            try {
                mSocket.shutdownInput();
                mSocket.shutdownOutput();
                mSocket.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
            mSocket = null;
        }
        if (br != null) {
            try {
                br.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
            br = null;
        }
        log.debug("call closeReader end");
    }

    private void openReader() {
        log.debug("call openReader");
        try {
            if (null == mSocket) {
                if (null == mServerSocket) {
                    mServerSocket = new LocalServerSocket(AUTOMMI_SOCKET_NAME);
                }
                mSocket = mServerSocket.accept();
                mSocket.setSoTimeout(60 * 1000);//设置超时时间60秒
            }
            br = new BufferedReader(new InputStreamReader(mSocket.getInputStream()));
        } catch (IOException e) {
            throw Exceptions.propagate(e);
        }
        log.debug("call openReader end");
    }

    @Override
    public void startGetStaProbeInfo() throws RemoteException {
        log.debug("call startGetStaProbeInfo");
        if (getStaSubscription != null && !getStaSubscription.isUnsubscribed())
            return;
        openReader();
        getStaSubscription = Observable.create(new Action1<Emitter<String[]>>() {
            private String lastStrs[] = new String[2];

            @Override
            public void call(final Emitter<String[]> emitter) {
                //注册广播，wifi关闭时停止探针
                final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
                    @Override
                    public void onReceive(Context context, Intent intent) {
                        log.debug("call BroadcastReceiver onReceive");
                        String action = intent.getAction();
                        if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
                            int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
                            log.debug("call BroadcastReceiver WIFI_P2P_STATE_CHANGED_ACTION state:{}", state);
                            if (state == WifiP2pManager.WIFI_P2P_STATE_DISABLED) {
                                emitter.onCompleted();
                            }
                        }
                    }
                };
                final Context context = mContext;
                emitter.setCancellation(new Cancellable() {
                    @Override
                    public void cancel() throws Exception {
                        log.debug("call cancel");
                        log.debug("call unregisterReceiver");
                        context.unregisterReceiver(broadcastReceiver);
                        closeReader();
                    }
                });
                IntentFilter mIntentFilter = new IntentFilter(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
                log.debug("call registerReceiver");
                context.registerReceiver(broadcastReceiver, mIntentFilter);

                //接受系统数据
                log.debug("<thread> start br.readLine");
                while (!getStaSubscription.isUnsubscribed()) {
                    try {
                        String recv_sta = br.readLine();
                        if (null == recv_sta) {
                            log.debug("<thread> recv_sta null");
                            throw new IOException();
                        }
//                        log.debug("<thread> read length:{}, data:{}", recv_sta.length(), recv_sta);
                        if (recv_sta.length() == 36) {
                            String[] strs = new String[2];
                            strs[0] = recv_sta.substring(5, 22);//mac
                            strs[1] = recv_sta.substring(32, 35);//rssi
                            if (lastStrs[0] != null && (!strs[0].equals(lastStrs[0]) || !strs[1].equals(lastStrs[1])))
                                emitter.onNext(lastStrs);//发送事件传递数据
                            lastStrs = strs;
//                            emitter.onNext(strs);
                        }
                    } catch (IOException e) {
                        if (getStaSubscription.isUnsubscribed())
                            break;
                        log.debug("<thread> catch IOException:{}", e.toString());
                        e.printStackTrace();
                        closeReader();
                        openReader();
                    }
                }
            }
        }, Emitter.BackpressureMode.BUFFER)
                .subscribeOn(Schedulers.io())
                .subscribe(new Action1<String[]>() {
                    private void OnProbeSta(String mac, String rssi, long time) {
                        Iterator<OnTaskStaListener> iterator = onTaskStaListenerSet.iterator();
                        while (iterator.hasNext()) {
                            OnTaskStaListener onTaskStaListener = iterator.next();
                            try {
                                onTaskStaListener.getWiFiProbeOfSta(mac, rssi, time);
                            } catch (Exception e) {
                                iterator.remove();
                                e.printStackTrace();
                            }
                        }
                    }

                    @Override
                    public void call(String[] strings) {
                        log.trace("call OnProbeSta, mac:{}, rssi:{}", strings[0], strings[1]);
                        OnProbeSta(strings[0], strings[1], System.currentTimeMillis());
                    }
                }, new Action1<Throwable>() {
                    @Override
                    public void call(Throwable throwable) {
                        throwable.printStackTrace();
                    }
                });

    }

    @Override
    public void closeWifiStaProbeInfo(OnSwitchListener icb) throws RemoteException {
        log.debug("call closeWifiStaProbeInfo");
        if (getStaSubscription != null && !getStaSubscription.isUnsubscribed()) {
            getStaSubscription.unsubscribe();
        }
        if (icb != null)
            icb.swich(ServiceResult.WiFiProbe_Stop_Succeed, "停止接收数据成功");
    }

    @Override
    public void registerStaCallback(OnTaskStaListener cb) throws RemoteException {
        log.debug("call registerStaCallback, cb:{}", cb);
        if (null == cb)
            return;
        for (OnTaskStaListener onTaskStaListener : onTaskStaListenerSet) {
            if (cb.asBinder() == onTaskStaListener.asBinder())
                return;
        }
        onTaskStaListenerSet.add(cb);
    }

    @Override
    public void unregisterStaCallback(OnTaskStaListener cb) throws RemoteException {
        log.debug("call unregisterStaCallback, cb:{}", cb);
        if (null == cb)
            return;
        Iterator<OnTaskStaListener> iterator = onTaskStaListenerSet.iterator();
        while (iterator.hasNext()) {
            OnTaskStaListener onTaskStaListener = iterator.next();
            if (onTaskStaListener.asBinder() == cb.asBinder())
                iterator.remove();
        }
    }

}
